/**
    Copyright (C) 2012 Guido Ludwig

    This file is part of JATT.
	http://code.google.com/p/jatt/

    JATT is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package de.guidoludwig.jatt.chain;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.chain.impl.ContextBase;

import com.jgoodies.validation.ValidationResult;

import de.guidoludwig.jatt.JATT;
import de.guidoludwig.jatt.util.AudioInfo;
import de.guidoludwig.jatt.util.ImageInfo;
import de.guidoludwig.jatt.util.JATTUtil;

/**
 * @author Guido Ludwig
 */
public class JATTContext extends ContextBase {

	private static final long serialVersionUID = -3569493546427056332L;

	public static final String PROPERTY_ALTERNATIVE_IMAGES = "alternativeImages";

	public static final String PROPERTY_FOLDER_IMAGE = "folderImage";

	public static final String PROPERTY_UNTAGGED = "untagged";
	public static final String PROPERTY_TAGGED = "tagged";
	public static final String PROPERTY_DIRECTORY = "directory";
	
	private final File directory;
	private final File workingDirectory;
	private final File artworkCollection;
	
	private final List<AudioInfo> tagged;
	private final List<AudioInfo> untagged;

	private ImageInfo folderImage;
	private final List<ImageInfo> alternativeImages;

	private ValidationResult validationResult;
	
	private boolean initialHasFolderImage;
	private boolean initialHasUntaggedFiles;

	public JATTContext(String directory) throws IOException {
		this(new File(directory), null);
	}

	public void backupInitial() {
		initialHasFolderImage = hasFolderImage();
		initialHasUntaggedFiles = untagged.size() > 0;
	}
	
	public JATTContext(File directory, File artworkCollection) throws IOException {
		this.directory = directory;
		if (!directory.exists()) {
			throw new IllegalArgumentException("Directory "
					+ directory.getAbsolutePath() + " does not exist");
		} else if (!directory.isDirectory()) {
			throw new IllegalArgumentException("Directory "
					+ directory.getAbsolutePath() + " is not a directory");
		}
		workingDirectory = JATTUtil.createTempDirectory();
		this.artworkCollection = artworkCollection;

		tagged = new ArrayList<AudioInfo>();
		untagged = new ArrayList<AudioInfo>();
		alternativeImages = new ArrayList<ImageInfo>();
	}

	public File getDirectory() {
		return directory;
	}
	public File getWorkingDirectory() {
		return workingDirectory;
	}
	public File getArtworkCollectionDirectory() {
		return artworkCollection;
	}
	public boolean isCollectingArtwork() {
		return artworkCollection != null;
	}

	public boolean hasTaggedFiles() {
		return tagged.size() > 0;
	}

	public List<ImageInfo> getAllImageInfo() {
		List<ImageInfo> all = new ArrayList<ImageInfo>(alternativeImages);
		if (folderImage != null) {
			all.add(folderImage);
		}
		return all;
	}

	public AudioInfo getFirstTagged() {
		return !hasTaggedFiles() ? null : tagged.get(0);
	}

	public boolean hasUntaggedFiles() {
		return untagged.size() > 0;
	}

	public List<AudioInfo> getTagged() {
		return Collections.unmodifiableList(tagged);
	}

	public void addAudio(File file) {
		AudioInfo info;
		try {
			info = new AudioInfo(file);
			if (info.isArtworkTagged()) {
				addToTagged(info);
			} else {
				addToUntagged(info);
			}
		} catch (Exception e) {
			JATT.error(e);
		}
	}
	
	private void addToTagged(AudioInfo newElement) {
		if (!tagged.add(newElement)) {
			throw new IllegalStateException(
					"Unable to add element to the List.");
		}
		JATT.debug("Added tagged : " + newElement.getFile().getName());
	}

	private void removeFromTagged(AudioInfo remElement) {
		if (!tagged.remove(remElement)) {
			throw new IllegalArgumentException("Element is not in the List.");
		}
	}

	public List<AudioInfo> getUntagged() {
		return Collections.unmodifiableList(untagged);
	}

	public List<AudioInfo> getAllAudioInfo() {
		List<AudioInfo> all = new ArrayList<AudioInfo>(tagged);
		all.addAll(untagged);
		return Collections.unmodifiableList(all);
	}

	public AudioInfo getFirst() {
		return !tagged.isEmpty() ? tagged.get(0) : untagged.get(0);
	}
	
	public String getArtistName() {
		AudioInfo info = getFirst();
		if (info == null) {
			return null;
		}
		if (!info.isArtistTagged()) {
			return null;
		}
		return info.getArtist();
	}
	public String getAlbumName() {
		AudioInfo info = getFirst();
		if (info == null) {
			return null;
		}
		if (!info.isAlbumTagged()) {
			return null;
		}
		return info.getAlbum();
	}

	public void moveToUntagged(AudioInfo audioInfo) {
		removeFromTagged(audioInfo);
		addToUntagged(audioInfo);
	}

	public void moveToTagged(AudioInfo audioInfo) {
		removeFromUntagged(audioInfo);
		addToTagged(audioInfo);
	}

	public void addToUntagged(AudioInfo newElement) {
		if (!untagged.add(newElement)) {
			throw new IllegalStateException(
					"Unable to add element to the List.");
		}
	}

	public void removeFromUntagged(AudioInfo remElement) {
		if (!untagged.remove(remElement)) {
			throw new IllegalArgumentException("Element is not in the List.");
		}
	}

	public ImageInfo getFolderImageInfo() {
		return folderImage;
	}
	public File getFolderImageFile() {
		return folderImage == null ? null : folderImage.getFile();
	}

	public void setFolderImage(File newFolderImage) {
		if (newFolderImage == null) {
			folderImage = null;
		} else {
			folderImage = new ImageInfo(newFolderImage);
		}
	}

	public boolean hasFolderImage() {
		return folderImage != null;
	}

	public List<ImageInfo> getAlternativeImages() {
		return Collections.unmodifiableList(alternativeImages);
	}

	public void addToAlternativeImages(File newElement) {
		if (!alternativeImages.add(new ImageInfo(newElement))) {
			throw new IllegalStateException(
					"Unable to add element to the List.");
		}
	}

	public void removeFromAlternativeImages(ImageInfo remElement) {
		if (!alternativeImages.remove(remElement)) {
			throw new IllegalArgumentException("Element is not in the List.");
		}
	}
	public void removeFromAlternativeImages(File candidate) {
		if (candidate == null) {
			throw new IllegalArgumentException("File to be removed must not be null");
		}
		ImageInfo imageInfo = findImageInfo(candidate);
		if (imageInfo == null) {
			throw new IllegalArgumentException(candidate.getAbsolutePath() + " is not registered as alternative image");
		}
		if (!alternativeImages.remove(imageInfo)) {
			throw new IllegalArgumentException("Element is not in the List.");
		}
	}

	private ImageInfo findImageInfo(File candidate) {
		if (candidate == null) {
			return null;
		}
		for (ImageInfo info : alternativeImages) {
			if (candidate.getAbsolutePath().equals(info.getFile().getAbsolutePath())) {
				return info;
			}
		}
		return null;
	}

	public ValidationResult getValidationResult() {
		return validationResult == null ? ValidationResult.EMPTY : validationResult;
	}

	public void setValidationResult(ValidationResult newResult) {
		validationResult = newResult;
	}

	public boolean isInitialHasFolderImage() {
		return initialHasFolderImage;
	}

	public boolean isInitialHasUntaggedFiles() {
		return initialHasUntaggedFiles;
	}


}
